//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++
// |  |  |__   |  |  | | | |  version 3.11.3
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#pragma once

#include <limits>  // numeric_limits
#include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/call_std/begin.hpp>
#include <nlohmann/detail/meta/call_std/end.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/json_fwd.hpp>
#include <string>  // char_traits
#include <tuple>   // tuple
#include <type_traits>  // false_type, is_constructible, is_integral, is_same, true_type
#include <utility>  // declval

NLOHMANN_JSON_NAMESPACE_BEGIN
/*!
@brief detail namespace with internal helper functions

This namespace collects functions that should not be exposed,
implementations of some @ref basic_json methods, and meta-programming helpers.

@since version 2.1.0
*/
namespace detail {

/////////////
// helpers //
/////////////

// Note to maintainers:
//
// Every trait in this file expects a non CV-qualified type.
// The only exceptions are in the 'aliases for detected' section
// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
//
// In this case, T has to be properly CV-qualified to constraint the function
// arguments (e.g. to_json(BasicJsonType&, const T&))

template <typename>
struct is_basic_json : std::false_type {};

NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};

// used by exceptions create() member functions
// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
// false_type otherwise
template <typename BasicJsonContext>
struct is_basic_json_context
    : std::integral_constant<
          bool,
          is_basic_json<typename std::remove_cv<typename std::remove_pointer<
              BasicJsonContext>::type>::type>::value ||
              std::is_same<BasicJsonContext, std::nullptr_t>::value> {};

//////////////////////
// json_ref helpers //
//////////////////////

template <typename>
class json_ref;

template <typename>
struct is_json_ref : std::false_type {};

template <typename T>
struct is_json_ref<json_ref<T>> : std::true_type {};

//////////////////////////
// aliases for detected //
//////////////////////////

template <typename T>
using mapped_type_t = typename T::mapped_type;

template <typename T>
using key_type_t = typename T::key_type;

template <typename T>
using value_type_t = typename T::value_type;

template <typename T>
using difference_type_t = typename T::difference_type;

template <typename T>
using pointer_t = typename T::pointer;

template <typename T>
using reference_t = typename T::reference;

template <typename T>
using iterator_category_t = typename T::iterator_category;

template <typename T, typename... Args>
using to_json_function = decltype(T::to_json(std::declval<Args>()...));

template <typename T, typename... Args>
using from_json_function = decltype(T::from_json(std::declval<Args>()...));

template <typename T, typename U>
using get_template_function = decltype(std::declval<T>().template get<U>());

// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template <typename BasicJsonType, typename T, typename = void>
struct has_from_json : std::false_type {};

// trait checking if j.get<T> is valid
// use this trait instead of std::is_constructible or std::is_convertible,
// both rely on, or make use of implicit conversions, and thus fail when T
// has several constructors/operator= (see
// https://github.com/nlohmann/json/issues/958)
template <typename BasicJsonType, typename T>
struct is_getable {
  static constexpr bool value =
      is_detected<get_template_function, const BasicJsonType &, T>::value;
};

template <typename BasicJsonType, typename T>
struct has_from_json<BasicJsonType, T, enable_if_t<!is_basic_json<T>::value>> {
  using serializer = typename BasicJsonType::template json_serializer<T, void>;

  static constexpr bool value =
      is_detected_exact<void, from_json_function, serializer,
                        const BasicJsonType &, T &>::value;
};

// This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
template <typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {};

template <typename BasicJsonType, typename T>
struct has_non_default_from_json<BasicJsonType, T,
                                 enable_if_t<!is_basic_json<T>::value>> {
  using serializer = typename BasicJsonType::template json_serializer<T, void>;

  static constexpr bool value =
      is_detected_exact<T, from_json_function, serializer,
                        const BasicJsonType &>::value;
};

// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
// Do not evaluate the trait when T is a basic_json type, to avoid template
// instantiation infinite recursion.
template <typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {};

template <typename BasicJsonType, typename T>
struct has_to_json<BasicJsonType, T, enable_if_t<!is_basic_json<T>::value>> {
  using serializer = typename BasicJsonType::template json_serializer<T, void>;

  static constexpr bool value =
      is_detected_exact<void, to_json_function, serializer, BasicJsonType &,
                        T>::value;
};

template <typename T>
using detect_key_compare = typename T::key_compare;

template <typename T>
struct has_key_compare
    : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {
};

// obtains the actual object key comparator
template <typename BasicJsonType>
struct actual_object_comparator {
  using object_t = typename BasicJsonType::object_t;
  using object_comparator_t =
      typename BasicJsonType::default_object_comparator_t;
  using type = typename std::conditional<has_key_compare<object_t>::value,
                                         typename object_t::key_compare,
                                         object_comparator_t>::type;
};

template <typename BasicJsonType>
using actual_object_comparator_t =
    typename actual_object_comparator<BasicJsonType>::type;

/////////////////
// char_traits //
/////////////////

// Primary template of char_traits calls std char_traits
template <typename T>
struct char_traits : std::char_traits<T> {};

// Explicitly define char traits for unsigned char since it is not standard
template <>
struct char_traits<unsigned char> : std::char_traits<char> {
  using char_type = unsigned char;
  using int_type = uint64_t;

  // Redefine to_int_type function
  static int_type to_int_type(char_type c) noexcept {
    return static_cast<int_type>(c);
  }

  static char_type to_char_type(int_type i) noexcept {
    return static_cast<char_type>(i);
  }

  static constexpr int_type eof() noexcept {
    return static_cast<int_type>(EOF);
  }
};

// Explicitly define char traits for signed char since it is not standard
template <>
struct char_traits<signed char> : std::char_traits<char> {
  using char_type = signed char;
  using int_type = uint64_t;

  // Redefine to_int_type function
  static int_type to_int_type(char_type c) noexcept {
    return static_cast<int_type>(c);
  }

  static char_type to_char_type(int_type i) noexcept {
    return static_cast<char_type>(i);
  }

  static constexpr int_type eof() noexcept {
    return static_cast<int_type>(EOF);
  }
};

///////////////////
// is_ functions //
///////////////////

// https://en.cppreference.com/w/cpp/types/conjunction
template <class...>
struct conjunction : std::true_type {};
template <class B>
struct conjunction<B> : B {};
template <class B, class... Bn>
struct conjunction<B, Bn...> : std::conditional<static_cast<bool>(B::value),
                                                conjunction<Bn...>, B>::type {};

// https://en.cppreference.com/w/cpp/types/negation
template <class B>
struct negation : std::integral_constant<bool, !B::value> {};

// Reimplementation of is_constructible and is_default_constructible, due to
// them being broken for std::pair and std::tuple until LWG 2367 fix (see
// https://cplusplus.github.io/LWG/lwg-defects.html#2367). This causes compile
// errors in e.g. clang 3.5 or gcc 4.9.
template <typename T>
struct is_default_constructible : std::is_default_constructible<T> {};

template <typename T1, typename T2>
struct is_default_constructible<std::pair<T1, T2>>
    : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {
};

template <typename T1, typename T2>
struct is_default_constructible<const std::pair<T1, T2>>
    : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {
};

template <typename... Ts>
struct is_default_constructible<std::tuple<Ts...>>
    : conjunction<is_default_constructible<Ts>...> {};

template <typename... Ts>
struct is_default_constructible<const std::tuple<Ts...>>
    : conjunction<is_default_constructible<Ts>...> {};

template <typename T, typename... Args>
struct is_constructible : std::is_constructible<T, Args...> {};

template <typename T1, typename T2>
struct is_constructible<std::pair<T1, T2>>
    : is_default_constructible<std::pair<T1, T2>> {};

template <typename T1, typename T2>
struct is_constructible<const std::pair<T1, T2>>
    : is_default_constructible<const std::pair<T1, T2>> {};

template <typename... Ts>
struct is_constructible<std::tuple<Ts...>>
    : is_default_constructible<std::tuple<Ts...>> {};

template <typename... Ts>
struct is_constructible<const std::tuple<Ts...>>
    : is_default_constructible<const std::tuple<Ts...>> {};

template <typename T, typename = void>
struct is_iterator_traits : std::false_type {};

template <typename T>
struct is_iterator_traits<iterator_traits<T>> {
 private:
  using traits = iterator_traits<T>;

 public:
  static constexpr auto value =
      is_detected<value_type_t, traits>::value &&
      is_detected<difference_type_t, traits>::value &&
      is_detected<pointer_t, traits>::value &&
      is_detected<iterator_category_t, traits>::value &&
      is_detected<reference_t, traits>::value;
};

template <typename T>
struct is_range {
 private:
  using t_ref = typename std::add_lvalue_reference<T>::type;

  using iterator = detected_t<result_of_begin, t_ref>;
  using sentinel = detected_t<result_of_end, t_ref>;

  // to be 100% correct, it should use
  // https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator and
  // https://en.cppreference.com/w/cpp/iterator/sentinel_for but reimplementing
  // these would be too much work, as a lot of other concepts are used
  // underneath
  static constexpr auto is_iterator_begin =
      is_iterator_traits<iterator_traits<iterator>>::value;

 public:
  static constexpr bool value = !std::is_same<iterator, nonesuch>::value &&
                                !std::is_same<sentinel, nonesuch>::value &&
                                is_iterator_begin;
};

template <typename R>
using iterator_t = enable_if_t<is_range<R>::value,
                               result_of_begin<decltype(std::declval<R &>())>>;

template <typename T>
using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;

// The following implementation of is_complete_type is taken from
// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
// and is written by Xiang Fan who agreed to using it in this library.

template <typename T, typename = void>
struct is_complete_type : std::false_type {};

template <typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};

template <typename BasicJsonType, typename CompatibleObjectType,
          typename = void>
struct is_compatible_object_type_impl : std::false_type {};

template <typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl<
    BasicJsonType, CompatibleObjectType,
    enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value &&
                is_detected<key_type_t, CompatibleObjectType>::value>> {
  using object_t = typename BasicJsonType::object_t;

  // macOS's is_constructible does not play well with nonesuch...
  static constexpr bool value =
      is_constructible<typename object_t::key_type,
                       typename CompatibleObjectType::key_type>::value &&
      is_constructible<typename object_t::mapped_type,
                       typename CompatibleObjectType::mapped_type>::value;
};

template <typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type
    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};

template <typename BasicJsonType, typename ConstructibleObjectType,
          typename = void>
struct is_constructible_object_type_impl : std::false_type {};

template <typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type_impl<
    BasicJsonType, ConstructibleObjectType,
    enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value &&
                is_detected<key_type_t, ConstructibleObjectType>::value>> {
  using object_t = typename BasicJsonType::object_t;

  static constexpr bool value =
      (is_default_constructible<ConstructibleObjectType>::value &&
       (std::is_move_assignable<ConstructibleObjectType>::value ||
        std::is_copy_assignable<ConstructibleObjectType>::value) &&
       (is_constructible<typename ConstructibleObjectType::key_type,
                         typename object_t::key_type>::value &&
        std::is_same<typename object_t::mapped_type,
                     typename ConstructibleObjectType::mapped_type>::value)) ||
      (has_from_json<BasicJsonType,
                     typename ConstructibleObjectType::mapped_type>::value ||
       has_non_default_from_json<
           BasicJsonType,
           typename ConstructibleObjectType::mapped_type>::value);
};

template <typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type
    : is_constructible_object_type_impl<BasicJsonType,
                                        ConstructibleObjectType> {};

template <typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type {
  static constexpr auto value =
      is_constructible<typename BasicJsonType::string_t,
                       CompatibleStringType>::value;
};

template <typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type {
  // launder type through decltype() to fix compilation failure on ICPC
#ifdef __INTEL_COMPILER
  using laundered_type = decltype(std::declval<ConstructibleStringType>());
#else
  using laundered_type = ConstructibleStringType;
#endif

  static constexpr auto value = conjunction<
      is_constructible<laundered_type, typename BasicJsonType::string_t>,
      is_detected_exact<typename BasicJsonType::string_t::value_type,
                        value_type_t, laundered_type>>::value;
};

template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {};

template <typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl<
    BasicJsonType, CompatibleArrayType,
    enable_if_t<
        is_detected<iterator_t, CompatibleArrayType>::value &&
        is_iterator_traits<iterator_traits<
            detected_t<iterator_t, CompatibleArrayType>>>::value &&
        // special case for types like std::filesystem::path whose iterator's
        // value_type are themselves c.f.
        // https://github.com/nlohmann/json/pull/3073
        !std::is_same<CompatibleArrayType,
                      detected_t<range_value_t, CompatibleArrayType>>::value>> {
  static constexpr bool value =
      is_constructible<BasicJsonType,
                       range_value_t<CompatibleArrayType>>::value;
};

template <typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type
    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};

template <typename BasicJsonType, typename ConstructibleArrayType,
          typename = void>
struct is_constructible_array_type_impl : std::false_type {};

template <typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl<
    BasicJsonType, ConstructibleArrayType,
    enable_if_t<std::is_same<ConstructibleArrayType,
                             typename BasicJsonType::value_type>::value>>
    : std::true_type {};

template <typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl<
    BasicJsonType, ConstructibleArrayType,
    enable_if_t<!std::is_same<ConstructibleArrayType,
                              typename BasicJsonType::value_type>::value &&
                !is_compatible_string_type<BasicJsonType,
                                           ConstructibleArrayType>::value &&
                is_default_constructible<ConstructibleArrayType>::value &&
                (std::is_move_assignable<ConstructibleArrayType>::value ||
                 std::is_copy_assignable<ConstructibleArrayType>::value) &&
                is_detected<iterator_t, ConstructibleArrayType>::value &&
                is_iterator_traits<iterator_traits<
                    detected_t<iterator_t, ConstructibleArrayType>>>::value &&
                is_detected<range_value_t, ConstructibleArrayType>::value &&
                // special case for types like std::filesystem::path whose
                // iterator's value_type are themselves c.f.
                // https://github.com/nlohmann/json/pull/3073
                !std::is_same<
                    ConstructibleArrayType,
                    detected_t<range_value_t, ConstructibleArrayType>>::value &&
                is_complete_type<detected_t<range_value_t,
                                            ConstructibleArrayType>>::value>> {
  using value_type = range_value_t<ConstructibleArrayType>;

  static constexpr bool value =
      std::is_same<value_type,
                   typename BasicJsonType::array_t::value_type>::value ||
      has_from_json<BasicJsonType, value_type>::value ||
      has_non_default_from_json<BasicJsonType, value_type>::value;
};

template <typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type
    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {
};

template <typename RealIntegerType, typename CompatibleNumberIntegerType,
          typename = void>
struct is_compatible_integer_type_impl : std::false_type {};

template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl<
    RealIntegerType, CompatibleNumberIntegerType,
    enable_if_t<std::is_integral<RealIntegerType>::value &&
                std::is_integral<CompatibleNumberIntegerType>::value &&
                !std::is_same<bool, CompatibleNumberIntegerType>::value>> {
  // is there an assert somewhere on overflows?
  using RealLimits = std::numeric_limits<RealIntegerType>;
  using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;

  static constexpr auto value =
      is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value &&
      CompatibleLimits::is_integer &&
      RealLimits::is_signed == CompatibleLimits::is_signed;
};

template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type
    : is_compatible_integer_type_impl<RealIntegerType,
                                      CompatibleNumberIntegerType> {};

template <typename BasicJsonType, typename CompatibleType, typename = void>
struct is_compatible_type_impl : std::false_type {};

template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type_impl<
    BasicJsonType, CompatibleType,
    enable_if_t<is_complete_type<CompatibleType>::value>> {
  static constexpr bool value =
      has_to_json<BasicJsonType, CompatibleType>::value;
};

template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type
    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};

template <typename T1, typename T2>
struct is_constructible_tuple : std::false_type {};

template <typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>>
    : conjunction<is_constructible<T1, Args>...> {};

template <typename BasicJsonType, typename T>
struct is_json_iterator_of : std::false_type {};

template <typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator>
    : std::true_type {};

template <typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType,
                           typename BasicJsonType::const_iterator>
    : std::true_type {};

// checks if a given type T is a template specialization of Primary
template <template <typename...> class Primary, typename T>
struct is_specialization_of : std::false_type {};

template <template <typename...> class Primary, typename... Args>
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};

template <typename T>
using is_json_pointer =
    is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;

// checks if A and B are comparable using Compare functor
template <typename Compare, typename A, typename B, typename = void>
struct is_comparable : std::false_type {};

template <typename Compare, typename A, typename B>
struct is_comparable<Compare, A, B,
                     void_t<decltype(std::declval<Compare>()(
                                std::declval<A>(), std::declval<B>())),
                            decltype(std::declval<Compare>()(
                                std::declval<B>(), std::declval<A>()))>>
    : std::true_type {};

template <typename T>
using detect_is_transparent = typename T::is_transparent;

// type trait to check if KeyType can be used as object key (without a
// BasicJsonType) see is_usable_as_basic_json_key_type below
template <typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef,
          bool RequireTransparentComparator = true,
          bool ExcludeObjectKeyType = RequireTransparentComparator,
          typename KeyType = uncvref_t<KeyTypeCVRef>>
using is_usable_as_key_type = typename std::conditional<
    is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value &&
        !(ExcludeObjectKeyType &&
          std::is_same<KeyType, ObjectKeyType>::value) &&
        (!RequireTransparentComparator ||
         is_detected<detect_is_transparent, Comparator>::value) &&
        !is_json_pointer<KeyType>::value,
    std::true_type, std::false_type>::type;

// type trait to check if KeyType can be used as object key
// true if:
//   - KeyType is comparable with BasicJsonType::object_t::key_type
//   - if ExcludeObjectKeyType is true, KeyType is not
//   BasicJsonType::object_t::key_type
//   - the comparator is transparent or RequireTransparentComparator is false
//   - KeyType is not a JSON iterator or json_pointer
template <typename BasicJsonType, typename KeyTypeCVRef,
          bool RequireTransparentComparator = true,
          bool ExcludeObjectKeyType = RequireTransparentComparator,
          typename KeyType = uncvref_t<KeyTypeCVRef>>
using is_usable_as_basic_json_key_type = typename std::conditional<
    is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
                          typename BasicJsonType::object_t::key_type,
                          KeyTypeCVRef, RequireTransparentComparator,
                          ExcludeObjectKeyType>::value &&
        !is_json_iterator_of<BasicJsonType, KeyType>::value,
    std::true_type, std::false_type>::type;

template <typename ObjectType, typename KeyType>
using detect_erase_with_key_type =
    decltype(std::declval<ObjectType &>().erase(std::declval<KeyType>()));

// type trait to check if object_t has an erase() member functions accepting
// KeyType
template <typename BasicJsonType, typename KeyType>
using has_erase_with_key_type = typename std::conditional<
    is_detected<detect_erase_with_key_type, typename BasicJsonType::object_t,
                KeyType>::value,
    std::true_type, std::false_type>::type;

// a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector)
template <typename T>
struct is_ordered_map {
  using one = char;

  struct two {
    char x
        [2];  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
  };

  template <typename C>
  static one test(decltype(&C::capacity));
  template <typename C>
  static two test(...);

  enum {
    value = sizeof(test<T>(nullptr)) == sizeof(char)
  };  // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
};

// to avoid useless casts (see
// https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
template <typename T, typename U,
          enable_if_t<!std::is_same<T, U>::value, int> = 0>
T conditional_static_cast(U value) {
  return static_cast<T>(value);
}

template <typename T, typename U,
          enable_if_t<std::is_same<T, U>::value, int> = 0>
T conditional_static_cast(U value) {
  return value;
}

template <typename... Types>
using all_integral = conjunction<std::is_integral<Types>...>;

template <typename... Types>
using all_signed = conjunction<std::is_signed<Types>...>;

template <typename... Types>
using all_unsigned = conjunction<std::is_unsigned<Types>...>;

// there's a disjunction trait in another PR; replace when merged
template <typename... Types>
using same_sign =
    std::integral_constant<bool, all_signed<Types...>::value ||
                                     all_unsigned<Types...>::value>;

template <typename OfType, typename T>
using never_out_of_range = std::integral_constant<
    bool, (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType))) ||
              (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T))>;

template <typename OfType, typename T,
          bool OfTypeSigned = std::is_signed<OfType>::value,
          bool TSigned = std::is_signed<T>::value>
struct value_in_range_of_impl2;

template <typename OfType, typename T>
struct value_in_range_of_impl2<OfType, T, false, false> {
  static constexpr bool test(T val) {
    using CommonType = typename std::common_type<OfType, T>::type;
    return static_cast<CommonType>(val) <=
           static_cast<CommonType>((std::numeric_limits<OfType>::max)());
  }
};

template <typename OfType, typename T>
struct value_in_range_of_impl2<OfType, T, true, false> {
  static constexpr bool test(T val) {
    using CommonType = typename std::common_type<OfType, T>::type;
    return static_cast<CommonType>(val) <=
           static_cast<CommonType>((std::numeric_limits<OfType>::max)());
  }
};

template <typename OfType, typename T>
struct value_in_range_of_impl2<OfType, T, false, true> {
  static constexpr bool test(T val) {
    using CommonType = typename std::common_type<OfType, T>::type;
    return val >= 0 &&
           static_cast<CommonType>(val) <=
               static_cast<CommonType>((std::numeric_limits<OfType>::max)());
  }
};

template <typename OfType, typename T>
struct value_in_range_of_impl2<OfType, T, true, true> {
  static constexpr bool test(T val) {
    using CommonType = typename std::common_type<OfType, T>::type;
    return static_cast<CommonType>(val) >=
               static_cast<CommonType>((std::numeric_limits<OfType>::min)()) &&
           static_cast<CommonType>(val) <=
               static_cast<CommonType>((std::numeric_limits<OfType>::max)());
  }
};

template <typename OfType, typename T,
          bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
          typename = detail::enable_if_t<all_integral<OfType, T>::value>>
struct value_in_range_of_impl1;

template <typename OfType, typename T>
struct value_in_range_of_impl1<OfType, T, false> {
  static constexpr bool test(T val) {
    return value_in_range_of_impl2<OfType, T>::test(val);
  }
};

template <typename OfType, typename T>
struct value_in_range_of_impl1<OfType, T, true> {
  static constexpr bool test(T /*val*/) { return true; }
};

template <typename OfType, typename T>
inline constexpr bool value_in_range_of(T val) {
  return value_in_range_of_impl1<OfType, T>::test(val);
}

template <bool Value>
using bool_constant = std::integral_constant<bool, Value>;

///////////////////////////////////////////////////////////////////////////////
// is_c_string
///////////////////////////////////////////////////////////////////////////////

namespace impl {

template <typename T>
inline constexpr bool is_c_string() {
  using TUnExt = typename std::remove_extent<T>::type;
  using TUnCVExt = typename std::remove_cv<TUnExt>::type;
  using TUnPtr = typename std::remove_pointer<T>::type;
  using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
  return (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value) ||
         (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
}

}  // namespace impl

// checks whether T is a [cv] char */[cv] char[] C string
template <typename T>
struct is_c_string : bool_constant<impl::is_c_string<T>()> {};

template <typename T>
using is_c_string_uncvref = is_c_string<uncvref_t<T>>;

///////////////////////////////////////////////////////////////////////////////
// is_transparent
///////////////////////////////////////////////////////////////////////////////

namespace impl {

template <typename T>
inline constexpr bool is_transparent() {
  return is_detected<detect_is_transparent, T>::value;
}

}  // namespace impl

// checks whether T has a member named is_transparent
template <typename T>
struct is_transparent : bool_constant<impl::is_transparent<T>()> {};

///////////////////////////////////////////////////////////////////////////////

}  // namespace detail
NLOHMANN_JSON_NAMESPACE_END
